home *** CD-ROM | disk | FTP | other *** search
/ Best Tools for JAVA / Best Tools for JAVA.iso / JAVA_ALL / IDE / SUBARTIC / SUB_ARCT / LIB / TEXT_DIS.JAV < prev    next >
Encoding:
Text File  |  1996-10-04  |  30.1 KB  |  962 lines

  1. package sub_arctic.lib;
  2.  
  3.  
  4. import sub_arctic.output.drawable;
  5. import sub_arctic.output.style;
  6. import sub_arctic.output.style_manager;
  7.  
  8. import java.awt.Font;
  9. import java.awt.FontMetrics;
  10. import java.awt.Color;
  11. import java.util.Vector;
  12.  
  13. /** 
  14.  * Text edit area displayer.  This class displays a multi-line area of text
  15.  * with a selection point or area in a fashion suitable for use by a small
  16.  * text editor interactor.  Selection positions are given as a line number
  17.  * and position with a line.  Positions with a line refer to the 
  18.  * spaces before the characters (numbered from 0).  So for example a 
  19.  * selection  from line 0, character 0 to line 0, character 0 places 
  20.  * the cursor before the first character being displayed,  while a 
  21.  * selection from line 1 character 1 to line 2 character 2 selects from 
  22.  * the second character of the second line, up to and including the second 
  23.  * character of the third line.  
  24.  * 
  25.  * @author Scott Hudson 
  26.  */
  27. public class text_display extends base_interactor {
  28.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  29.  
  30.   /** Extra vertical spacing at top and bottom of text */
  31.   protected int _v_spacing = 3;
  32.  
  33.   /** 
  34.    * Extra vertical spacing at top and bottom of text.
  35.    * @return int the vertical spacing value. 
  36.    */
  37.   public int v_spacing() {return _v_spacing;}
  38.  
  39.   /** 
  40.    * Set extra vertical spacing at top and bottom of text. 
  41.    * @param int v the new spacing value.
  42.    */
  43.   public void set_v_spacing(int v) 
  44.     {
  45.       if (v != _v_spacing)
  46.     {
  47.       _v_spacing = v;
  48.       damage_self();
  49.     }
  50.     }
  51.  
  52.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  53.  
  54.   /** Extra horizontal spacing at left and right of text */
  55.   protected int _h_spacing = 3;
  56.  
  57.   /** 
  58.    * Extra horizontal spacing at left and right of text. 
  59.    * @return int the horizontal spacing value. 
  60.    */
  61.   public int h_spacing() {return _h_spacing;}
  62.  
  63.   /** 
  64.    * Set extra horizontal spacing at left and right of text.
  65.    * @param int v the new spacing value.
  66.    */
  67.   public void set_h_spacing(int v) 
  68.     {
  69.       if (v != _h_spacing)
  70.     {
  71.       _h_spacing = v;
  72.       damage_self();
  73.     }
  74.     }
  75.     
  76.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  77.  
  78.   /** Cached font metrics object for the current font */
  79.   protected FontMetrics _metric;
  80.  
  81.   /** Font that interactor displays in */
  82.   protected Font _font;
  83.  
  84.   // note: later we might just store the metrics object, since we can get the
  85.   // front from that
  86.  
  87.   /** 
  88.    * Font that interactor displays in 
  89.    * @return Font the font this interactor is using; will return the system's 
  90.    *              default font if you don't specify a font
  91.    */
  92.   public Font font() {return _font;}
  93.  
  94.   /** 
  95.    * Set font that interactor displays in 
  96.    * @param Font fnt the font to use for this interactor (use null to get the 
  97.    *                 system's default font 
  98.    */
  99.   public void set_font(Font fnt)
  100.     {
  101.       /* if they pass a null font we use the default */
  102.       if (fnt == null) fnt = style_manager.default_font();
  103.  
  104.       /* if this is not a change, bail out early */
  105.       if (fnt.equals(_font)) return;
  106.  
  107.       /* store the font and stash a metrics object for it */
  108.       _font = fnt;
  109.       _metric = manager.get_metrics(_font);
  110.  
  111.       damage_self();
  112.     }
  113.  
  114.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  115.  
  116.   /** Text to be displayed stored as a Vector of Strings */
  117.   protected Vector _text = new Vector();
  118.  
  119.   /** 
  120.    * Text to be displayed stored as a Vector of Strings.  
  121.    * This should normally be treated as read-only. 
  122.    * @return Vector the array of strings that this object is displaying.
  123.    */
  124.   public Vector text() {return _text;}
  125.  
  126.   /** 
  127.    * Set text contents from a single string with lines terminated 
  128.    * by newlines or carriage returns. 
  129.    * @param String text the text to display.
  130.    */
  131.   public void set_text(String txt) 
  132. {
  133.       /* break text into lines and use that for content */
  134.       _text = break_into_lines(txt);
  135.  
  136.       /* since we changed the text, refresh the screen */
  137.       /* there is no selection */
  138.       set_selection(NO_SELECTION, NO_SELECTION, NO_SELECTION, NO_SELECTION);
  139.       damage_self();
  140.     }
  141.  
  142.    //had:
  143.    //* @exception bad_value if initialized with a non-string value.
  144.  
  145.   /** 
  146.    * Set text contents from Vector of Strings. 
  147.    * @param Vector txt the array of strings to display.
  148.    */
  149.   public void set_text(Vector txt) 
  150. {
  151.       /* convert null text to empty text */
  152.       if (txt == null) txt = new Vector();
  153.  
  154.       /* first verify that the text looks ok */
  155.       for (int i = 0; i < txt.size(); i++)
  156.     if (!(txt.elementAt(i) instanceof String))
  157.       throw new sub_arctic_error("Initialization with non-string in set_text()");
  158.  
  159.       /* if everything went well, set the text vector to a copy of the input */
  160.       _text = (Vector)txt.clone();
  161.  
  162.       /* since we changed the text, refresh the screen */
  163.       /* there is no selection */
  164.       set_selection(NO_SELECTION, NO_SELECTION, NO_SELECTION, NO_SELECTION);
  165.       damage_self();
  166.     }
  167.  
  168.    //had:
  169.    //* @exception bad_value if initialized with a non-string value.
  170.  
  171.   /** 
  172.    * Get a single string with lines terminated by the given string.
  173.    * @param String terminator the line terminator for the return value.
  174.    * @return String a string with the contents of this object (separated by 
  175.    *                the parameter).
  176.    */
  177.   public String get_string(String terminator)
  178.     {
  179.       StringBuffer result = new StringBuffer();
  180.  
  181.       /* change null terminator into empty separator */
  182.       if (terminator == null) terminator = "";
  183.  
  184.       /* walk over line vector concatenating each line onto result */
  185.       for (int i = 0; i < text().size(); i++)
  186.     {
  187.       result.append((String)text().elementAt(i));
  188.       result.append(terminator);
  189.     }
  190.  
  191.       return result.toString();
  192.     }
  193.  
  194.   /** 
  195.    * Do a human readable dump of the text and selection to System.out  
  196.    */
  197.   public void dump_text()
  198.     {
  199.       int i;
  200.       String line;
  201.  
  202.       /* if we have no selection, just print the lines */
  203.       if (selection_start_line() == NO_SELECTION)
  204.     {
  205.       for (i = 0; i < text().size(); i++)
  206.         System.out.println((String)text().elementAt(i));
  207.     }
  208.       else
  209.     {
  210.           /* do lines before the one where selection starts */
  211.           for (i = 0; i < selection_start_line(); i++)
  212.         System.out.println((String)text().elementAt(i));
  213.  
  214.       /* extract line with start of selection */
  215.           line = (String)text().elementAt(i);
  216.  
  217.           /* print up to selection and marker for start of selection */
  218.           System.out.print(line.substring(0,selection_start_pos()));
  219.           System.out.print("**[");
  220.  
  221.       /* does the selections start and end on one line? */
  222.       if (selection_start_line() == selection_end_line())
  223.         {
  224.           /* print the selected text and end marker */
  225.           System.out.print(
  226.         line.substring(selection_start_pos(),selection_end_pos()));
  227.           System.out.print("]**");
  228.     
  229.           /* and the remainder of the line */
  230.           System.out.println(line.substring(selection_end_pos()));
  231.         }
  232.       else
  233.         {
  234.           /* print remainder of the line */
  235.           System.out.println(line.substring(selection_start_pos()));
  236.  
  237.           /* print lines that are completely selected */
  238.           for (i = selection_start_line()+1; i < selection_end_line(); i++)
  239.         System.out.println((String)text().elementAt(i));
  240.  
  241.           /* extract line selection ends on */
  242.               line = (String)text().elementAt(selection_end_line());
  243.  
  244.           /* print selected text and end marker */
  245.           System.out.print(
  246.         line.substring(0,selection_end_pos()));
  247.           System.out.print("]**");
  248.     
  249.           /* and the remainder of the line */
  250.           System.out.println(line.substring(selection_end_pos()));
  251.         }
  252.  
  253.       /* finally print all non-selected lines after the selection */
  254.       for (i = selection_end_line()+1; i < text().size(); i++)
  255.         System.out.println((String)text().elementAt(i));
  256.     }
  257.     }
  258.  
  259.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  260.  
  261.   /** 
  262.    * Convert a single string into a series of line strings stored in a 
  263.    * Vector.  Lines are delimited by newlines or carriage returns. 
  264.    *
  265.    * @param String all_text the text to break up into lines
  266.    * @param Vector the array of lines of the broken up text
  267.    */
  268.   public static Vector break_into_lines(String all_text)
  269.     {
  270.       Vector result = new Vector();
  271.       String rest;
  272.       int pos, nl1, nl2, nl;
  273.  
  274.       /* catch null string and treat as empty */
  275.       if (all_text == null) all_text = "";
  276.  
  277.       pos = 0; 
  278.       for (pos = 0; ; pos = nl+1)
  279.     {
  280.       /* find first line break after current position */
  281.       nl1 = all_text.indexOf('\n',pos);
  282.       nl2 = all_text.indexOf('\r',pos);
  283.       if (nl1 < nl2 || nl2 == -1)
  284.         nl = nl1;
  285.       else
  286.         nl = nl2;
  287.  
  288.       /* if there is none append any non-empty last line and we are done */
  289.       if (nl == -1)
  290.         {
  291.           /* pull out the remaining substring and append it as a line */
  292.           rest = all_text.substring(pos);
  293.           if (rest.length() > 0)
  294.             result.addElement(rest);
  295.  
  296.           /* make sure we have at least one line */
  297.           if (result.size() == 0) result.addElement("");
  298.  
  299.           return result;
  300.         }
  301.           else
  302.         {
  303.           /* otherwise append that line and keep trying */
  304.           result.addElement(all_text.substring(pos,nl));
  305.         }
  306.     }
  307.     }
  308.  
  309.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  310.  
  311.   /** Constant for a special selection point used to denote that there is no
  312.    *  selection. */
  313.   public static final int NO_SELECTION = -1;
  314.  
  315.   /** Constant used to denote that the selection is at the end of a line or 
  316.    *  line is the last one in the text.
  317.    */
  318.   public static final int SELECT_END = -2;
  319.  
  320.   /** Start line of the current selection.  */
  321.   protected int _selection_start_line = 0;
  322.  
  323.   /** Start line of the current selection.  */
  324.   public int selection_start_line() {return _selection_start_line;} 
  325.  
  326.   /** Position of start of selection within the start line. */ 
  327.   protected int _selection_start_pos = 0;
  328.  
  329.   /** Position of start of selection within the start line. */ 
  330.   protected int selection_start_pos() {return _selection_start_pos;}
  331.  
  332.   /** Ending line of the current selection.  */
  333.   protected int _selection_end_line = 0;
  334.  
  335.   /** Ending line of the current selection.  */
  336.   public int selection_end_line() {return _selection_end_line;} 
  337.  
  338.   /** Position of end of selection within the ending line. */ 
  339.   protected int _selection_end_pos = 0;
  340.  
  341.   /** Position of end of selection within the ending line. */ 
  342.   protected int selection_end_pos() {return _selection_end_pos;}
  343.  
  344.   /** 
  345.    * Set the current selection.  The special value NO_SELECTION can be coded
  346.    * in any position to denote that there is no current selection (in that 
  347.    * case the other parameters are ignored).  The special value SELECT_END
  348.    * may be applied to either a line or a character position to denote the 
  349.    * last line, or the position after the last character respectively. 
  350.    * 
  351.    * @param int st_line the starting line of the new selection.
  352.    * @param int st_pos the starting position of the new selection.
  353.    * @param int end_line the ending line of the new selection.
  354.    * @param int end_pos the ending position of the new selection.
  355.    */
  356.   public void set_selection(int st_line, int st_pos, int end_line, int end_pos)
  357.     {
  358.       int temp;
  359.  
  360.       /* if we have no selection, set that everywhere */
  361.       if (st_line == NO_SELECTION || st_pos == NO_SELECTION || 
  362.       end_line == NO_SELECTION || end_pos == NO_SELECTION)
  363.     {
  364.       st_line = st_pos = end_line = end_pos = NO_SELECTION;
  365.     }
  366.  
  367.       /* replace SELECT_END special value in lines */
  368.       if (st_line == SELECT_END)  st_line = text().size()-1;
  369.       if (end_line == SELECT_END) end_line = text().size()-1;
  370.  
  371.       /* force lines into valid range */
  372.       if (st_line < 0 && st_line != NO_SELECTION)   st_line = 0;
  373.       if (end_line < 0 && end_line != NO_SELECTION) end_line = 0;
  374.       if (st_line > text().size()-1)  st_line = text().size()-1;
  375.       if (end_line > text().size()-1) end_line = text().size()-1;
  376.  
  377.       /* replace SELECT_END special value in positions */
  378.       if (st_pos == SELECT_END)   
  379.     st_pos = ((String)text().elementAt(st_line)).length();
  380.       if (end_pos == SELECT_END)   
  381.     end_pos = ((String)text().elementAt(end_line)).length();
  382.  
  383.       /* force positions into range */
  384.       if (st_pos < 0 && st_pos != NO_SELECTION)   st_pos = 0;
  385.       if (end_pos < 0 && end_pos != NO_SELECTION) end_pos = 0;
  386.       if (st_line != NO_SELECTION &&
  387.       st_pos > ((String)text().elementAt(st_line)).length())
  388.     st_pos = ((String)text().elementAt(st_line)).length();
  389.       if (end_line != NO_SELECTION &&
  390.       end_pos > ((String)text().elementAt(end_line)).length())
  391.     end_pos = ((String)text().elementAt(end_line)).length();
  392.  
  393.       /* make sure we are ordered properly */
  394.       if (end_line < st_line || 
  395.      (end_line == st_line && end_pos < st_pos))
  396.     {
  397.       temp = end_line;
  398.       end_line = st_line;
  399.       st_line = temp;
  400.       temp = end_pos;
  401.       end_pos = st_pos;
  402.       st_pos = temp;
  403.     }
  404.  
  405.       /* if this is a change, do the assignment and ask for redraw */
  406.       if (end_line != _selection_end_line || end_pos != _selection_end_pos ||
  407.           st_line != _selection_start_line || st_pos != _selection_start_pos)
  408.     {
  409.       _selection_end_line   = end_line;
  410.       _selection_end_pos    = end_pos;
  411.       _selection_start_line = st_line;
  412.       _selection_start_pos  = st_pos;
  413.       damage_self();
  414.     }
  415.     }
  416.  
  417.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  418.  
  419.   /** Constant used to store boxed flag within interactor flags */
  420.   public static final int BOXED = FIRST_FREE_FLAG;
  421.  
  422.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  423.  
  424.   /** 
  425.    * Does the interactor have a box drawn around it.
  426.    * @return boolean true if this interactor is boxed.
  427.    */
  428.  
  429.   public boolean boxed()
  430.     {
  431.       return flag_is_set(BOXED);
  432.     }
  433.  
  434.   /** 
  435.    * Set the flag indicating whether interactor is drawn with a surrounding
  436.    *  box. 
  437.    * @param boolean box true if this interactor is boxed.
  438.    */
  439.   public void set_boxed(boolean bxv)
  440.     {
  441.       /* if we have a change, set the bit and ask for redraw */
  442.       if (bxv != boxed())
  443.     {
  444.       set_flag_bit(BOXED, bxv);
  445.       damage_self();
  446.     }
  447.     }
  448.  
  449.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  450.  
  451.   /** 
  452.    * Compute a size based on current content.
  453.    */
  454.   public void size_by_content()
  455.     {
  456.       int hv, wv, max_w, i;
  457.  
  458.       /* compute the height */
  459.       hv = _metric.getHeight() * text().size() + 2*v_spacing();
  460.  
  461.       /* find the max width */
  462.       max_w = 0;
  463.       for (i = 0; i < text().size(); i++)
  464.     {
  465.       /* measure the line and see if its biggest so far */
  466.       wv = _metric.stringWidth((String)text().elementAt(i));
  467.       if (wv > max_w) max_w = wv;
  468.     }
  469.       
  470.       /* add in the border */
  471.       max_w += 2*h_spacing();
  472.  
  473.       /* if this is a change, set the size */
  474.       if (h() != hv || w() != max_w)
  475.     set_size(max_w, hv);
  476.     }
  477.  
  478.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  479.  
  480.   /** 
  481.    * Parts that we intrinsically constrain.  Here we modify what our 
  482.    * super types result by removing part_a from the set.
  483.    * @return int a bitset indicating all parts that are intrinsically 
  484.    *             constrained.
  485.    */
  486.   public int intrinsic_constraints()
  487.     {
  488.       return super.intrinsic_constraints() & ~PART_A;
  489.     }
  490.  
  491.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  492.  
  493.   /** 
  494.    * Return the value of the part_a component of this object.  In our case 
  495.    * this is stored in _first_line. 
  496.    * @return int the value of part_a (AKA first_line).
  497.    */
  498.   public int part_a()
  499.     {
  500.       /* Make sure its up to date and in range then return it */
  501.       eval_part_a();
  502.       return _first_line;
  503.     }
  504.  
  505.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  506.  
  507.   /** 
  508.    * Set part_a value directly bypassing the constraint system (but doing 
  509.    * damage).  This should normally only be done by the constraint system 
  510.    * or some other part of the system which takes care of marking things 
  511.    * out-of-date, etc. itself.  In this case part_a is stored in _first_line.
  512.    *
  513.    * @param int v the new value.
  514.    */
  515.   protected void set_raw_part_a(int v) 
  516. {
  517.       /* don't do anything unless this is a change */
  518.       if (v != _first_line)
  519.     {
  520.       /* make change and do damage */
  521.           _first_line = v;
  522.           damage_self();
  523.     }
  524.     }
  525.  
  526.    //had:
  527.    //* @exception general PROPAGATED
  528.  
  529.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  530.  
  531.   /** 
  532.    * Set the part_a component of this object.  In our case this is stored in
  533.    * _first_line.  
  534.    *
  535.    * @param int v the new value
  536.    */
  537.   public void set_part_a(int v) 
  538. {
  539.       /* if this has a constraint throw an exception */
  540.       if ((active_constraints() & PART_A) != 0)
  541.         throw new sub_arctic_error(
  542.       "Attempt to assign value to constrained part_a " +
  543.       "(AKA text_display.first_line)");
  544.  
  545.       /* don't do anything unless this is a change */
  546.       if (v != _first_line)
  547.     {
  548.       set_raw_part_a(v);
  549.       mark_part_a_ood();
  550.     }
  551.     }
  552.  
  553.    //had:
  554.    //* @exception cannot_assign if the value is constrained.
  555.    //* @exception general PROPAGATED
  556.  
  557.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  558.  
  559.   /** 
  560.    * First line to display.  This is tied to part_a of this object so it
  561.    * can be constrained and/or exported to constraint.  If this is negative,
  562.    * we still display the 0th line at the top and if this goes past the end
  563.    * we display nothing.
  564.    */
  565.   protected int _first_line = 0;
  566.  
  567.   /** 
  568.    * First line to display.  This is tied to part_a of this object so it
  569.    * can be constrained and/or exported to constraint.  If this is negative,
  570.    * we still display the 0th line at the top and if this goes past the end
  571.    * we display nothing.
  572.    *
  573.    * @return int the first line offset.
  574.    */
  575.   public int first_line() {return part_a();}
  576.  
  577.   /** 
  578.    * Set the first line to display.  This is tied to part_a of this object so it
  579.    * can be constrained and/or exported to constraint.  If this is negative,
  580.    * we still display the 0th line at the top and if this goes past the end
  581.    * we display nothing.
  582.    *
  583.    * @param int frst_ln the first line to display.
  584.    */
  585.   public void first_line(int frst_ln) 
  586. {
  587.       set_part_a(frst_ln);
  588.     }
  589.  
  590.    //had:
  591.    //* @exception cannot assign if part_a has a constraint attached.
  592.    //* @exception general
  593.  
  594.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  595.  
  596.   /** 
  597.    * Full constructor with explicit size.  Text contents is provided by 
  598.    *  one string with lines separated by newlines or carriage returns. 
  599.    * @param int     xv       x position of this interactor.
  600.    * @param int     yv       y position of this interactor.
  601.    * @param int     wv       width of this interactor.
  602.    * @param int     hv       height of this interactor.
  603.    * @param String  contents the text to display in this box.
  604.    * @param Font    fnt      the font to use for drawing these strings.
  605.    * @param boolean boxed    true if this object should have a box around it.
  606.    */
  607.   public text_display(
  608.     int xv, int yv, int wv, int hv,
  609.     String           contents,
  610.     Font             fnt,
  611.     boolean          boxed) 
  612. {
  613.       super(xv,yv,wv,hv);
  614.       set_font(fnt);
  615.       set_text(contents);
  616.       set_boxed(boxed);
  617.       set_selection(NO_SELECTION,0,0,0);
  618.     }
  619.  
  620.    //had:
  621.    //* @exception general PROPAGATED
  622.  
  623.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  624.  
  625.   /** 
  626.    * Full constructor with size determined by initial text.  Text contents 
  627.    * is provided by one string with lines separated by newlines or carriage
  628.    * returns. 
  629.    *
  630.    * @param int     xv       x position of this interactor.
  631.    * @param int     yv       y position of this interactor.
  632.    * @param String  contents the text to display in this box.
  633.    * @param Font    fnt      the font to use for drawing these strings.
  634.    * @param boolean boxed    true if this object should have a box around it.
  635.    */
  636.   public text_display(
  637.     int xv, int yv, 
  638.     String           contents,
  639.     Font             fnt,
  640.     boolean          boxed) 
  641. {
  642.       super(xv,yv);
  643.  
  644.       /* set the instance vars */
  645.       set_font(fnt);
  646.       set_text(contents);
  647.       set_boxed(boxed);
  648.       set_selection(NO_SELECTION,0,0,0);
  649.  
  650.       /* compute a size based on the content */
  651.       size_by_content();
  652.     }
  653.  
  654.    //had:
  655.    //* @exception general PROPAGATED
  656.  
  657.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  658.  
  659.   /** 
  660.    * Constructor with computed size, default font, and default 
  661.    * boxed status. 
  662.    *
  663.    * @param int    xv       x position of this interactor.
  664.    * @param int    yv       y position of this interactor.
  665.    * @param String contents the text to display in this box.
  666.    */
  667.   public text_display(int xv, int yv, String contents) 
  668. {
  669.       this(xv,yv,contents, null, false);
  670.     }
  671.  
  672.    //had:
  673.    //* @exception general PROPAGATED
  674.  
  675.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  676.  
  677.   /** X position of current line.  This is used internally only during 
  678.    *  drawing.
  679.    */
  680.   protected static int xpos = 0;
  681.  
  682.   /** Y position of current line .  This is used internally only during 
  683.    *  drawing.
  684.    */
  685.   protected static int ypos = 0;
  686.  
  687.   /** Max Y position we need to do text drawing at (taking into account the
  688.    *  ascent of the font).  Any line of text whose baseline is past this
  689.    *  value will not show up and doesn't need to be drawn.  This is used 
  690.    *  internally only during drawing and is normally set to the height of 
  691.    *  the area plus the ascent of the font.
  692.    */
  693.   protected static int ypos_cutoff = 0;
  694.  
  695.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  696.  
  697.   /** 
  698.    * Draw a series of lines of unhighlighted text.  The static variables 
  699.    * xpos and ypos are used here to keep track of current line position and 
  700.    * communicate that between subsequent calls.  We assume here that the 
  701.    * background has been cleared, the font has been set and that the current
  702.    * color is set right for drawing text.
  703.    * 
  704.    * @param drawable d      the surface to do the drawing on.
  705.    * @param int      st_ln  starting line.
  706.    * @param int      end_ln ending line.
  707.    */
  708.   protected void draw_norm_lines(drawable d, int st_ln, int end_ln)
  709.     {
  710.       /* if we are already past the bottom bail out early. */
  711.       if (ypos > ypos_cutoff) return;
  712.  
  713.       /* start at beginning of line */
  714.       xpos = h_spacing();
  715.       for (int i = st_ln; i <= end_ln; i++)
  716.     {
  717.       /* draw only once we get to the first line */
  718.       if (i >= first_line())
  719.         {
  720.               d.drawString((String)text().elementAt(i), xpos, ypos);
  721.               ypos += _metric.getHeight();
  722.         }
  723.     }
  724.     }
  725.  
  726.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  727.  
  728.    /** 
  729.     * Draw line that is partially highlighted.  The highlight runs from the 
  730.     * given starting position to the given ending position (or SELECT_END
  731.     * if the highlight goes past end of line).  The static variables xpos and
  732.     * ypos are used here to keep track of current line position and 
  733.     * communicate that between subsequent calls.  We assume here that the
  734.     * background has been cleared and the font set.
  735.     *
  736.     * @param drawable d       the surface to do the drawing on.
  737.     * @param int      ln_num  the line number of the split line.
  738.     * @param int      st_pos  the position in the line of the start of the 
  739.     *                         split.
  740.     * @param int      end_pos the position in the line of the end of the split.
  741.     */
  742.    protected void draw_split_line(
  743.      drawable d, 
  744.      int ln_num, 
  745.      int st_pos, 
  746.      int end_pos)
  747.      {
  748.        String line, part;
  749.        int endx;
  750.  
  751.        /* if we are past the end or haven't gotten to the beginning bail now. */
  752.        if (ypos > ypos_cutoff || ln_num < first_line()) return;
  753.  
  754.        /* start at beginning of line */
  755.        xpos = h_spacing();
  756.  
  757.        /* draw unhighlighted part of line */
  758.        line = (String)text().elementAt(ln_num);
  759.  
  760.        /* if we have an unhighlighted leading part, draw that */
  761.        if (st_pos > 0)
  762.      {
  763.            part = line.substring(0,st_pos);
  764.            d.drawString(part, xpos, ypos);
  765.            xpos += _metric.stringWidth(part);
  766.      }
  767.  
  768.        /* if highlight is past end stop at w() otherwise calculate stop point */
  769.        if (end_pos == SELECT_END)
  770.      {
  771.        part = line.substring(st_pos);
  772.        endx = w();
  773.      }
  774.        else 
  775.      {
  776.        part = line.substring(st_pos,end_pos);
  777.        endx = xpos + _metric.stringWidth(part);
  778.      }
  779.  
  780.        /* draw highlight rect from 1/2 leading above to 1/2 leading below */
  781.        d.setColor(Color.black);
  782.        d.fillRect(xpos, ypos -_metric.getAscent()-(_metric.getLeading()/2), 
  783.           endx-xpos, _metric.getHeight());
  784.  
  785.        /* now draw text over that in white */
  786.        d.setColor(Color.white);
  787.        d.drawString(part, xpos,ypos);
  788.        xpos = endx;
  789.  
  790.        /* finally draw non-highlighted tail (if any) */
  791.        if (end_pos != SELECT_END)
  792.      {
  793.        part = line.substring(end_pos);
  794.        d.setColor(Color.black);
  795.        d.drawString(part, xpos,ypos);
  796.      }
  797.  
  798.        /* set up for the next line */
  799.        ypos += _metric.getHeight();
  800.        xpos = h_spacing();
  801.      }
  802.  
  803.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  804.  
  805.    /** 
  806.     * Draw a series of fully highlighted lines.  The static variables xpos and
  807.     * ypos are used here to keep track of current line position and 
  808.     * communicate that between subsequent calls.  We assume here that the
  809.     * background has been cleared and the font set.
  810.     * 
  811.     * @param drawable d        the surface to do the drawing on.
  812.     * @param int      first_ln the line number of the first highlighted line.
  813.     * @param int      last_ln  the line number of the last highlighted line.
  814.     */
  815.    protected void draw_highlighted_lines(drawable d, int first_ln, int last_ln)
  816.      {
  817.        int num = last_ln - Math.max(first_ln, first_line()) + 1;
  818.  
  819.        /* if we have no lines or we are past the end bail now */
  820.        if (num <= 0 || ypos > ypos_cutoff) return;
  821.  
  822.        /* draw the background highlight */
  823.        d.setColor(Color.black);
  824.        d.fillRect(xpos, ypos - _metric.getAscent() - (_metric.getLeading()/2), 
  825.           w(), num*_metric.getHeight());
  826.  
  827.        /* draw the text over the top in white */
  828.        d.setColor(Color.white);
  829.        for (int i = first_ln; i <= last_ln; i++)
  830.      {
  831.        /* draw only if we have made it to at least the first line */
  832.        if (i >= first_line())
  833.          {
  834.            d.drawString((String)text().elementAt(i), xpos, ypos);
  835.            ypos += _metric.getHeight();
  836.          }
  837.      }
  838.  
  839.        /* reset the color for the next guy */
  840.        d.setColor(Color.black);
  841.      }
  842.  
  843.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  844.  
  845.    /** 
  846.     * Draw image of text with selection and optional box 
  847.     * @param drawable d the drawable to work on
  848.     */
  849.    protected void draw_self_local(drawable d) 
  850. {
  851.     String line;
  852.     int xloc, sel_y;
  853.     style cs=style_manager.current_style();
  854.     int dvs=cs.drawable_vertical_space(),
  855.       dhs=cs.drawable_horizontal_space();
  856.     
  857.     /* enough space for the snazzy style stuff? */
  858.     if ((v_spacing()>=dvs) &&
  859.         (h_spacing()>=dhs)) {
  860.       /* there is enough */
  861.       cs.drawable_prepare_rect(d,0,0,w(),h(),false, true);
  862.       /* use the default system background color for text */
  863.       d.setColor(style_manager.default_color_scheme().text_background());
  864.       /* fill in the rect, but be sure to not go over the beveling */
  865.       d.fillRect(dhs,dvs,w()-(2*dhs),h()-(2*dvs));
  866.     } else {
  867.       /* clear the rectangle behind us */
  868.       d.setColor(style_manager.default_color_scheme().text_background());
  869.       d.fillRect(0,0,w()-1,h()-1);
  870.     }
  871.  
  872.     /* set font to our font, and start drawing in foreground */
  873.     d.setFont(font());
  874.     d.setColor(style_manager.default_color_scheme().foreground());
  875.  
  876.     /* establish the bottom cutoff value to end drawing text */
  877.     ypos_cutoff = h() + _metric.getAscent();
  878.  
  879.     /* set the initial drawing position */
  880.         xpos = h_spacing();
  881.         ypos = v_spacing() + _metric.getAscent();
  882.  
  883.     /* if we have no selection, just draw the text */
  884.     if (selection_start_line() == NO_SELECTION)
  885.       {
  886.         draw_norm_lines(d, 0, text().size()-1);
  887.       }
  888.     /* if we have point selection draw normal text then an insert line */
  889.     else if (selection_start_line() == selection_end_line() &&
  890.          selection_start_pos()  == selection_end_pos())
  891.       {
  892.         draw_norm_lines(d, 0, text().size()-1);
  893.         line = (String)text().elementAt(selection_start_line());
  894.         xloc = _metric.stringWidth(line.substring(0,selection_start_pos()));
  895.         sel_y = v_spacing()+
  896.          (selection_start_line() - first_line())*_metric.getHeight();
  897.         d.drawLine(xloc + h_spacing(),sel_y, 
  898.                xloc + h_spacing(), sel_y + _metric.getHeight());
  899.       }
  900.     else
  901.       {
  902.         /* draw normal lines up to line with selection */
  903.         draw_norm_lines(d, 0, selection_start_line()-1);
  904.  
  905.         /* draw highlight */
  906.  
  907.         /* is selection all on one line? */
  908.         if (selection_start_line() == selection_end_line())
  909.           {
  910.         /* just draw the highlight all on one line */
  911.         draw_split_line(d, selection_start_line(), 
  912.                         selection_start_pos(), selection_end_pos());
  913.           }
  914.         else 
  915.           {
  916.         /* draw line with highlight from start to end of line */
  917.             draw_split_line(d, selection_start_line(), 
  918.                     selection_start_pos(), SELECT_END);
  919.  
  920.         /* draw fully highlighted lines */
  921.         draw_highlighted_lines(d, selection_start_line()+1, 
  922.                       selection_end_line()-1);
  923.  
  924.         /* draw rest of highlight on the last line */
  925.         draw_split_line(d, selection_end_line(), 0,selection_end_pos());
  926.           }
  927.  
  928.         /* draw normal lines after highlight */
  929.         draw_norm_lines(d, selection_end_line()+1, text().size()-1);
  930.  
  931.       }
  932.  
  933.     /* draw the border rect if needed */
  934.         if (boxed()) 
  935.       {
  936.             d.setColor(Color.black);
  937.         d.drawRect(0,0,w()-1,h()-1);
  938.       }
  939.      }
  940.  
  941.     //had:
  942.     //* @exception general PROPAGATED
  943.  
  944.   /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  945. };
  946. /*=========================== COPYRIGHT NOTICE ===========================
  947.  
  948. This file is part of the subArctic user interface toolkit.
  949.  
  950. Copyright (c) 1996 Scott Hudson and Ian Smith
  951. All rights reserved.
  952.  
  953. The subArctic system is freely available for most uses under the terms
  954. and conditions described in 
  955.   http://www.cc.gatech.edu/gvu/ui/sub_arctic/sub_arctic/doc/usage.html 
  956. and appearing in full in the lib/interactor.java source file.
  957.  
  958. The current release and additional information about this software can be 
  959. found starting at: http://www.cc.gatech.edu/gvu/ui/sub_arctic/
  960.  
  961. ========================================================================*/
  962.